/**************************************************************
    Problem: 衡阳八中1036
****************************************************************/
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<sstream>
#include<cmath>
#include<vector>
#include<string>
#include<map>
#include<set>
#include<queue>
#include<stack>
using namespace std;
typedef long long ll;
const int inf=1012345678;
#define clr(x,a) memset(x,a,sizeof(x))
 
 
inline int rd(){int x;scanf("%d",&x);return x;}
const int maxn =  40000;
const int maxe = 101000;
int n,m;
/****************下面是建立深搜的树*********************/
int first[maxe],next[maxe],E[maxe],M;
void init()
{
    M=0;
    for(int i=0; i<=n+3; i++)
        first[i]=-1;
}
void _ins(int a,int b)
{
    M++;
    next[M]=first[a];
    first[a]=M;
    E[M]=b;
}
void ins(int a,int b)
{
    _ins(a,b);
    _ins(b,a);
}
/****************上面是建立深搜的树*********************/
/*******************下面是建立链的线段树********************/
struct node
{
    int a,add,maxx,sum;
}qtr[maxe*4],*tl,*head[maxe];
//nodeval保存节点信息，trsz表示线段树的长度,belong表示该节点属于哪个线段树pos表示在这颗线段树的位置.
int nodeval[maxe],trsz[maxe],cas,dep[maxe],belong[maxe],pos[maxe];
//vis 深搜 的时候判断重复搜没和 son是判断儿子个数
int vis[maxe],son[maxn],rmq[maxn][20],LOG=16;
 
void pushup(node*tr,int nod)
{
    tr[nod].sum=tr[nod<<1].sum+tr[nod<<1|1].sum;
    tr[nod].maxx=max(tr[nod<<1].maxx,tr[nod<<1|1].maxx);
}
 
void insert(node *tr,int nod,int l,int r,int x,int y,int a)
{//把值x到y的值改成a
    if(l==r)
    {
        tr[nod].a=tr[nod].maxx=tr[nod].sum=a;
        return ;
    }
    int mid=(l+r)/2;
    if(x<=mid)
        insert(tr,nod<<1,l,mid,x,y,a);
    if(mid<y)
        insert(tr,nod<<1|1,mid+1,r,x,y,a);
    pushup(tr,nod);
}
void maketree(int u,int h)
{
    int i,rt=u;
    for(i=1; i<h; i++)   rt=rmq[rt][0];//找到根 
    head[rt]=tl;
    for(i=0; i<h*4; i++)//初始话树
     head[rt][i].a=head[rt][i].add=head[rt][i].sum=head[rt][i].maxx=0;
         
    tl+=h*4;//偏移量加值
    trsz[rt]=h;//记录这颗树有多少个元素
    for(i=h; i>=1; i--)
    {
        belong[u]=rt;//当前节点属于那棵树
        pos[u]=i;//当前节点所在的这颗树第几个元素
        insert(head[rt],1,1,h,i,i,nodeval[u]);
        u=rmq[u][0];
    }
}
void change(int x,int y)//将节点x的值改为y
{
    int fa=belong[x];
    nodeval[x]=y;
    insert(head[fa],1,1,trsz[fa],pos[x],pos[x],y);
}
 
int findsum(node*tr,int nod,int l,int r,int x,int y)
{//找到线段树中x到y的和
    if(x<=l && r<=y)
        return tr[nod].sum;
    int mid=(l+r)/2,ans=0;
    if(x<=mid)
        ans+=findsum(tr,nod<<1,l,mid,x,y);
    if(mid<y)
        ans+=findsum(tr,nod<<1|1,mid+1,r,x,y);
    pushup(tr,nod);
    return ans;
}
 
int getsum(int a,int b,int &is)
{//找到树链中x到y的和
    int ans=0,fa,fb;
    is=0;
    while(a!=b)
    {
        fa=belong[a]; fb=belong[b];
        if(fa!=fb)
        {
            ans+=findsum(head[fb],1,1,trsz[fb],1,pos[b]);
            b=rmq[fb][0];
        }
        else
        {
            is=1;
            ans+=findsum(head[fb],1,1,trsz[fb],pos[a],pos[b]);
            break;
        }
    }
    return ans;
}
 
int findmax(node*tr,int nod,int l,int r,int x,int y)
{//找到线段树中x到y的最大值
    if(x<=l && r<=y)
        return tr[nod].maxx;
    int mid=(l+r)/2,ans=-inf;
    if(x<=mid)
        ans=max(ans,findmax(tr,nod<<1,l,mid,x,y));
    if(mid<y)
        ans=max(ans,findmax(tr,nod<<1|1,mid+1,r,x,y));
    pushup(tr,nod);
    return ans;
}
int getmax(int a,int b)
{//找到树链中x到y的最大值
    if(a==b)    return nodeval[a];
    int ans=-inf,fa,fb;
    while(a!=b)
    {
        fa=belong[a],fb=belong[b];
        if(fa!=fb)
        {
            ans=max(ans,findmax(head[fb],1,1,trsz[fb],1,pos[b]));
            b=rmq[fb][0];
        }
        else
        {
            ans=max(ans,findmax(head[fb],1,1,trsz[fb],pos[a],pos[b]));
            break;
        }
    }
    return ans;
}
 
void dfs1(int u)
{//第一次深搜找儿子的个数
    int i,j,e;
    vis[u]=cas;
    for(i=1; i<LOG; i++) rmq[u][i]=rmq[rmq[u][i-1]][i-1];
    son[u]=1;
    for(e=first[u]; e!=-1; e=next[e])
    if(vis[E[e]]<cas)
    {
        int v=E[e];
        dep[v]=dep[u]+1;
        rmq[v][0]=u;
        dfs1(v);
        son[u]+=son[v];
    }
}
void dfs2(int u,int h)//第二次dfs划分轻重边
{
    int i,j,e,v;
    vis[u]=cas;
    int now=-1,tp=0;
    for(e=first[u]; e!=-1; e=next[e])
    if(vis[E[e]]<cas && tp <son[E[e]])//找重边
    {
        tp=son[E[e]];
        now=E[e];
    }
    if(now==-1)//找到一条重边的节点,建立线段树
    {
        maketree(u,h);
        return ;
    }
    dfs2(now,h+1);//找下一条重边
    for(e=first[u];e!=-1 ; e=next[e])
    {
        v=E[e];
        if(vis[v]<cas && v!=now)
            dfs2(v,1);
    }
}
void split(int rt)//两次深搜进行重边划分
{
    tl=qtr;//头赋值
    cas++;
    dep[rt]=1;//根节点
    memset(rmq,0,sizeof(rmq));
    dfs1(rt);
    cas++;
    dfs2(rt,1);
}
int lca(int a,int b)
{//算出a 和b的公共祖先
    int i,tp=dep[b]-dep[a];
    if(tp<0)
    {
        tp=-tp;
        swap(a,b);
    }
    for(i=0; i<LOG; i++)
    if(tp&(1<<i)) b=rmq[b][i];
    if(a==b)    return a;
    for(i=LOG; i>=0; i--)
    if(rmq[a][i]!=rmq[b][i])
    {
        a=rmq[a][i];
        b=rmq[b][i];
    }
    return rmq[a][0];
}
int main()
{
  
    int i,j,k,p;
    while(scanf("%d",&n)!=EOF)
    {
        int x,y,z;
        init();
        for(i=1; i<n; i++)
        {
            scanf("%d%d",&x,&y);
            ins(x,y);
        }
        for(i=1; i<=n; i++)
            nodeval[i]=rd();
     /********************/
        split(1);
     /********************/
        scanf("%d",&m);
        int fa,h1,h2,ans;
        char ch[20];
        for(i=0; i<m; i++)
        {
            scanf(" %s%d%d",ch,&x,&y);
            fa=lca(x,y);
            if(ch[1]=='H')
            {
                change(x,y);
            }
            else if(ch[1]=='S')
            {
               ans=getsum(fa,x,h1)+getsum(fa,y,h2);//求一条链的和，
                if(h1==0 && h2==0)//若两个都是非重边，特殊处理顶点
                    ans+=nodeval[fa];       
                printf("%d\n",ans);
            }
            else
            {
               ans=max(getmax(fa,x),getmax(fa,y));
               ans=max(ans,nodeval[fa]);//若两个都是非重边特殊处理顶点
               printf("%d\n",ans);
            }
        }
    }
}
